package server

import (
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"net"

	"chatRoom/src/proto"
)

//客户端发来的连接，buf为读取信息流
type ClientProcess struct {
	conn net.Conn
	buf  [8192]byte
}

func (c *ClientProcess) Process() (err error) {
	for {
		var msg proto.Messgae
		msg, err = c.readPackage()
		if err != nil {
			return err
		}

		err = c.processMsg(msg)
		if err != nil {
			fmt.Println("Process msg failed, err:", err)
			continue
		}
	}
}
func (c *ClientProcess) readPackage() (msg proto.Messgae, err error) {
	n, err := c.conn.Read(c.buf[0:4])
	if n != 4 {
		err = errors.New("Read header failed")
		return
	}
	fmt.Println("read package: ", c.buf[0:4])

	var packLen uint32
	packLen = binary.BigEndian.Uint32(c.buf[0:4])
	fmt.Printf("receive len: %d", packLen)

	n, err = c.conn.Read(c.buf[0:packLen])
	if n != int(packLen) {
		err = errors.New("Read body failed")
		return
	}

	fmt.Printf("receive data: %s\n", string(c.buf[0:packLen]))
	err = json.Unmarshal(c.buf[0:packLen], &msg)
	if err != nil {
		fmt.Println("unmarshal failed, err:", err)
	}
	return
}

func (c *ClientProcess) writePackage(data []byte) (err error) {
	packLen := uint32(len(data))

	binary.BigEndian.PutUint32(c.buf[0:4], packLen)
	n, err := c.conn.Write(c.buf[0:4])
	if err != nil {
		fmt.Println("write data failed")
		return
	}

	n, err = c.conn.Write(data)
	if err != nil {
		fmt.Println("write data failed")
		return
	}

	if n != int(packLen) {
		fmt.Println("write data not finished")
		err = errors.New("write data not finished")
		return
	}

	return
}

func (c *ClientProcess) processMsg(msg proto.Messgae) (err error) {
	switch msg.Cmd {
	case proto.UserLogin:
		err = c.login(msg)
	case proto.UserRegister:
		err = c.register(msg)
	default:
		err = errors.New("unsupport message")
		return
	}
	return
}

func (c *ClientProcess) login(msg proto.Messgae) (err error) {
	defer func() {
		c.loginResp(err)
	}()

	fmt.Printf("recv user login request, data:%v", msg)
	var cmd proto.LoginCmd
	err = json.Unmarshal([]byte(msg.Data), &cmd)
	if err != nil {
		return
	}

	_, err = Mgr.Login(cmd.Id, cmd.Passwd)
	if err != nil {
		return
	}
	clientMgr.AddClient(cmd.Id, c)
	return
}

func (c *ClientProcess) register(msg proto.Messgae) (err error) {
	var cmd proto.RegisterCmd
	err = json.Unmarshal([]byte(msg.Data), &cmd)
	if err != nil {
		return err
	}

	err = Mgr.Register(&cmd.User)
	if err != nil {
		fmt.Println("register failed")
		return
	}

	return
}

func (c *ClientProcess) loginResp(err error) {
	var respMsg proto.Messgae
	respMsg.Cmd = proto.UserLoginRes

	var loginRes proto.LoginCmdRes
	loginRes.Code = 200

	userMap := clientMgr.GetAllUsers()
	for uID := range userMap {
		loginRes.User = append(loginRes.User, uID)
	}

	if err != nil {
		loginRes.Code = 500
		loginRes.Error = fmt.Sprintf("%v", err)
	}

	data, err := json.Marshal(loginRes)
	if err != nil {
		fmt.Println("marshal failed, ", err)
		return
	}

	respMsg.Data = string(data)
	data, err = json.Marshal(respMsg)
	if err != nil {
		fmt.Println("marshal failed, ", err)
		return
	}

	err = c.writePackage(data)
	if err != nil {
		fmt.Println("send failed, ", err)
		return
	}

}
